home *** CD-ROM | disk | FTP | other *** search
/ Gamers Delight 2 / Gamers Delight 2.iso / Aminet / game / role / AMDoc_0_9.lha / AMDoc / Programming.txt < prev    next >
Text File  |  1995-01-21  |  69KB  |  1,862 lines

  1. AmigaMUD, Copyright 1995 by Chris Gray
  2.  
  3.  
  4.         Programming in the AmigaMUD System
  5.  
  6. Introduction
  7.  
  8.  
  9. The AmigaMUD system contains a complete programming system for a
  10. structured programming language. This language is used to program any
  11. MUD scenarios, quests, puzzles, etc. The AmigaMUD system contains
  12. facilities for parsing, executing, storing, retrieving and pretty-
  13. printing code in the language. Although intended for writing MUD
  14. scenarios, the language can easily be used for other purposes.
  15.  
  16. Although the interpreter is reasonably efficient, it is by no means as
  17. fast as true compiled code. Programmers should keep this in mind when
  18. using the language - things that are practical in, say, C, may not be
  19. practical in AmigaMUD.
  20.  
  21. AmigaMUD programming is accessed though one of the client programs,
  22. just like playing a scenario is. Only characters with status 'wizard'
  23. or 'apprentice' can directly access the programming features.
  24. Characters enabled as builders can indirectly access them by writing
  25. actions as described in the building document.
  26.  
  27. The AmigaMUD programming language does not contain any language
  28. constructs for doing input/output, graphics, sound, etc. Instead, the
  29. system contains a large number of builtin functions which perform
  30. these activities. Other builtin functions perform utility operations
  31. such as returning the length of a string, taking a substring,
  32. returning the current time and date, etc.
  33.  
  34. Most AmigaMUD programming involves writing functions. These functions
  35. are stored in the system database and are automatically retrieved as
  36. needed (e.g. to call them or print them out). AmigaMUD functions can
  37. have parameters and can return a result. They can also be recursive,
  38. although this is quite rare in a MUD scenario.
  39.  
  40. All AmigaMUD code executes in the server program, MUDServ, on the host
  41. computer. Lexical scanning, parsing, and editing all happen on the
  42. client computers. Parsed functions are sent from the client to the
  43. server as a "compiled" bytestream. Pretty-printing is done on the
  44. host computer, and the results are sent to the client as text. Because
  45. the server computer can never wait for any client (the human player
  46. might get a phone call in the middle of typing in a function!), some
  47. operations, such as input, are done differently than in other
  48. languages.
  49.  
  50. When using the standard scenario, a wizard or apprentice can go into
  51. programming, or wizard mode, by typing the 'wizard' command. The
  52. prompt will change to "> ". In this mode, input typed in is assumed to
  53. be statements in the programming language, definitions of functions,
  54. or one of a few simple wizard-mode commands. For reference, a
  55. statement to get out of wizard mode consists of:
  56.  
  57.     Normal().
  58.  
  59. This, of course, is only valid when the prompt is "> ", i.e. when no
  60. partial statement has been entered, and the user is not in the middle
  61. of typing in a function definition.
  62.  
  63. If the input statement does not fit on a single line, it can be
  64. continued on as many lines as needed. On lines other than the first,
  65. the prompt will change to ": ". The input statement is ended with a
  66. period, as in the above example. If the input statement is in fact an
  67. expression, i.e. it returns a value, then the system will print out
  68. that value. For example:
  69.  
  70.     > 2 + 3.
  71.     ==> 5
  72.  
  73. Not all values can be printed in any meaningful way. Function and
  74. thing (database entity) values are printed either symbolically (if the
  75. system can find a symbol for them) or as a hexadecimal number.
  76.  
  77. Each input line entered by any user is subject to an execution time
  78. limit, which can be controlled by the MUD administrator (SysAdmin).
  79. Running out of time will result in the execution being stopped, and a
  80. traceback of the called functions being produced. Other run-time
  81. errors, such as dividing by zero, produce a similar abort and
  82. traceback.
  83.  
  84. The following sections of this document give some examples of AmigaMUD
  85. programming. It is assumed that the reader already knows something
  86. about programming, or is a fast learner - this document does not try
  87. to teach programming to a novice. Readers are not expected to fully
  88. understand these examples - they are just a random sampling to show
  89. the flavour of AmigaMUD programming.
  90.  
  91.  
  92. Example - the Towers of Hanoi
  93.  
  94.  
  95. Here is a log of entering, printing and running the classic "Towers of
  96. Hanoi" function. Commentary is separated off and enclosed in square
  97. brackets. For those not familiar with this computer programming
  98. classic, the story goes something like this:
  99.  
  100.     There is a monastery near Hanoi where there live a group of monks
  101.     dedicated to keeping the universe running. They do this by
  102.     continually moving flat disks around on a set of three pegs. The
  103.     disks are round, and have a hole in the middle so that they can
  104.     slide onto the pegs. At the beginning of the universe, all 64
  105.     disks were on the left-most peg, with the widest disk on the
  106.     bottom, and the narrowest one on the top. When the monks have
  107.     succeeded in moving all of the disks to the right-hand peg, the
  108.     universe will end. They can only move one disk at a time, and must
  109.     never place a wider disk on top of a narrower one. The monks must
  110.     move the disks as fast as they can.
  111.  
  112. input> wizard
  113.  
  114.     [I was initially in normal playing mode. I used the 'wizard'
  115.     command to get into wizard mode so I can program.]
  116.  
  117. > private proc hanoi(int n; string from, to, using)void:
  118. *** expecting identifier for proc parameter name
  119. *** expecting ',', ';' or ')' after proc parameter
  120. : .
  121. *** expecting 'corp' to end proc definition
  122. Errors detected, proc "hanoi" not created.
  123.  
  124.     [I accidentally tried to use a reserved word as a parameter name.
  125.     I decided to abort the entering of the function by typing a '.'.
  126.     This doesn't always work - sometimes closing parentheses or
  127.     constructs are also needed. Note that the prompt changed to ": "
  128.     while I was entering the function definition.]
  129.  
  130. > private proc hanoi(int n; string fromStr, toStr, usingStr)void:
  131. Postman has arrived from the north.
  132. : if n ~= 0 then
  133. Postman heads into the passageway.
  134. :  hanoi(n - 1, fromStr, usingStr, toStr);
  135. :  Print("Move disk " + IntToString(n) + " from " + fromStr + " peg to " +
  136. :   toStr + " peg.\n");
  137. :  hanoi(n - 1, usingStr, toStr, fromStr);
  138. : fi;
  139. : corp
  140.  
  141.     [Being in wizard mode doesn't take your character out of the
  142.     scenario, hence I still saw messages about Postman passing
  143.     through. It is often wise to go somewhere private when doing
  144.     serious wizarding, so that you aren't interrupted.]
  145.  
  146. > describe hanoi.
  147. hanoi: proc, owner Merlin, useCount 2:
  148. proc hanoi(int n; string fromStr, toStr, usingStr)void:
  149.     if n ~= 0 then
  150.     hanoi(n - 1, fromStr, usingStr, toStr);
  151.     Print("Move disk " + IntToString(n) + " from " + fromStr + " peg to "
  152.          + toStr + " peg.\n");
  153.     hanoi(n - 1, usingStr, toStr, fromStr);
  154.     fi;
  155. corp
  156.  
  157.     [The exact form in which I entered the function is not preserved.
  158.     The function is stored internally as a byte stream, and is
  159.     "pretty-printed" by the system as needed. I used the 'describe'
  160.     wizard-mode command to display the function.]
  161.  
  162. > hanoi(0, "left", "right", "center").
  163.  
  164.     [Now I call the function. This is a directly entered statement in
  165.     the programming language. With 'n' equal to 0, the function does
  166.     nothing, and, since it returns nothing ("void"), nothing is
  167.     printed.]
  168.  
  169. > hanoi(1, "left", "right", "center").
  170. Move disk 1 from left peg to right peg.
  171.  
  172.     [With 'n' equal to 1, there is one line of output.]
  173.  
  174. > hanoi(2, "left", "right", "center").
  175. Move disk 1 from left peg to center peg.
  176. Move disk 2 from left peg to right peg.
  177. Move disk 1 from center peg to right peg.
  178. > hanoi(3, "left", "right", "center").
  179. Move disk 1 from left peg to right peg.
  180. Move disk 2 from left peg to center peg.
  181. Move disk 1 from right peg to center peg.
  182. Move disk 3 from left peg to right peg.
  183. Move disk 1 from center peg to left peg.
  184. Move disk 2 from center peg to right peg.
  185. Move disk 1 from left peg to right peg.
  186.  
  187.     [The number of lines of output is equal to 2 to the power of 'n',
  188.     minus one. Thus, we need not fear for the imminent end of the
  189.     world. Even if the monks can move one disk per second, the time
  190.     needed to complete the task, 2 to the power of 64, minus one, is a
  191.     very long time indeed!]
  192.  
  193. > Normal().
  194. input> bye
  195.  
  196.     [I go back into normal mode, and exit.]
  197.  
  198.  
  199. Example - Code to Draw the Streets Area
  200.  
  201.  
  202. define tp_streets proc drawStreets()void:
  203.  
  204.     if not KnowsEffect(nil, STREETS_ID) then
  205.     DefineEffect(nil, STREETS_ID);
  206.     GSetImage(nil, "streets");
  207.     IfFound(nil);
  208.         GShowImage(nil, "", 0, 0, 160, 100, 0, 0);
  209.     Else(nil);
  210.         GSetPen(nil, C_DARK_GREY);
  211.         GAMove(nil, 0, 0);
  212.         GRectangle(nil, 159, 99, true);
  213.  
  214.         GSetPen(nil, C_LIGHT_GREY);
  215.         GAMove(nil, 0, 0);
  216.         GRectangle(nil, 69, 41, true);
  217.         GAMove(nil, 89, 0);
  218.         GRectangle(nil, 70, 41, true);
  219.         GAMove(nil, 0, 57);
  220.         GRectangle(nil, 69, 42, true);
  221.         GAMove(nil, 89, 57);
  222.         GRectangle(nil, 70, 42, true);
  223.  
  224.         GSetPen(nil, C_DARK_BROWN);
  225.         GAMove(nil, 0, 0);
  226.         GRectangle(nil, 62, 35, true);
  227.         GAMove(nil, 96, 0);
  228.         GRectangle(nil, 63, 35, true);
  229.         GAMove(nil, 0, 63);
  230.         GRectangle(nil, 62, 36, true);
  231.  
  232.         GSetPen(nil, C_WHITE);
  233.         GAMove(nil, 79, 0);
  234.         GRDraw(nil, 0, 35);
  235.         GAMove(nil, 0, 49);
  236.         GRDraw(nil, 62, 0);
  237.         GAMove(nil, 97, 49);
  238.         GRDraw(nil, 62, 0);
  239.         GAMove(nil, 79, 63);
  240.         GRDraw(nil, 0, 36);
  241.  
  242.         GSetPen(nil, C_BLACK);
  243.         GAMove(nil, 62, 13);
  244.         VerticalDoor();
  245.         GAMove(nil, 96, 1);
  246.         VerticalDoor();
  247.         GAMove(nil, 96, 13);
  248.         VerticalDoor();
  249.         GAMove(nil, 96, 25);
  250.         VerticalDoor();
  251.         GAMove(nil, 101, 35);
  252.         HorizontalDoor();
  253.         GAMove(nil, 122, 35);
  254.         HorizontalDoor();
  255.         GAMove(nil, 143, 35);
  256.         HorizontalDoor();
  257.         GAMove(nil, 62, 65);
  258.         VerticalDoor();
  259.         GAMove(nil, 62, 77);
  260.         VerticalDoor();
  261.         GAMove(nil, 62, 89);
  262.         VerticalDoor();
  263.         GAMove(nil, 5, 63);
  264.         HorizontalDoor();
  265.         GAMove(nil, 26, 63);
  266.         HorizontalDoor();
  267.         GAMove(nil, 47, 63);
  268.         HorizontalDoor();
  269.  
  270.         GSetPen(nil, C_LIGHT_GREEN);
  271.         GAMove(nil, 96, 63);
  272.         GRectangle(nil, 56, 30, true);
  273.         GSetPen(nil, C_LIGHT_GREY);
  274.         GAMove(nil, 121, 63);
  275.         GRectangle(nil, 5, 36, true);
  276.         GAMove(nil, 111, 69);
  277.         GRectangle(nil, 25, 18, true);
  278.         GSetPen(nil, C_BLUE);
  279.         GAMove(nil, 118, 74);
  280.         GRectangle(nil, 11, 8, true);
  281.         GSetPen(nil, C_GOLD);
  282.         GAMove(nil, 123, 78);
  283.         GCircle(nil, 1, true);
  284.         GAMove(nil, 124, 78);
  285.         GCircle(nil, 1, true);
  286.  
  287.         GSetPen(nil, C_DARK_BROWN);
  288.         GAMove(nil, 103, 72);
  289.         GRectangle(nil, 7, 12, true);
  290.         GAMove(nil, 137, 72);
  291.         GRectangle(nil, 8, 12, true);
  292.         GSetPen(nil, C_BLACK);
  293.         GAMove(nil, 110, 74);
  294.         VerticalDoor();
  295.         GAMove(nil, 137, 74);
  296.         VerticalDoor();
  297.  
  298.         GSetPen(nil, C_FOREST_GREEN);
  299.         GAMove(nil, 100, 67);
  300.         GCircle(nil, 5, true);
  301.         GAMove(nil, 135, 67);
  302.         GCircle(nil, 4, true);
  303.         GAMove(nil, 145, 68);
  304.         GCircle(nil, 5, true);
  305.         GAMove(nil, 114, 91);
  306.         GCircle(nil, 3, true);
  307.         GAMove(nil, 107, 90);
  308.         GCircle(nil, 3, true);
  309.         GAMove(nil, 99, 91);
  310.         GCircle(nil, 3, true);
  311.         GAMove(nil, 149, 80);
  312.         GCircle(nil, 3, true);
  313.         GAMove(nil, 148, 87);
  314.         GCircle(nil, 3, true);
  315.         GAMove(nil, 142, 91);
  316.         GCircle(nil, 3, true);
  317.         GAMove(nil, 133, 90);
  318.         GCircle(nil, 3, true);
  319.     Fi(nil);
  320.     EndEffect();
  321.     fi;
  322.     CallEffect(nil, STREETS_ID);
  323. corp;
  324.  
  325.  
  326. Recall from earlier documents that the "MUD" client program can cache
  327. effects, such as the graphics for the streets area. The server program
  328. keeps track of which active clients currently know which effects. The
  329. code here is asking the server if the current client knows the effect
  330. identified by 'STREETS_ID'. If it doesn't, then that effect is
  331. defined. The effect is actually like a little program itself. A
  332. graphics image called "streets" is requested. If it is found on the
  333. client machine, then it is shown, otherwise a rough rendering of the
  334. image is produced using rectangles, lines, circles, etc. Note that
  335. this decision is made in the client program, since the server cannot
  336. wait for the result of that decision. The rough drawing of the streets
  337. area can be summarized as:
  338.  
  339.     - fill the entire image area with dark grey
  340.     - draw four rectangles of light grey as sidewalks
  341.     - draw three smaller rectangles of dark brown as the buildings
  342.     - draw lines of white down the middle of the roads
  343.     - draw a bunch of black doors. 'VerticalDoor' and 'HorizontalDoor'
  344.     are scenario functions which in turn use effects to draw the
  345.     standard vertical and horizontal doors.
  346.     - draw a light green rectangle to be the body of the park
  347.     - draw a pair of overlapping light grey rectangles to be the
  348.     sidewalks in the park
  349.     - draw the blue fountain with the gold mermaid in it
  350.     - draw two dark brown buildings with black doors
  351.     - draw a bunch of forest green trees
  352.  
  353. After the STREETS_ID effect is defined (if it wasn't already), it is
  354. called up. The result of all of this is that the first time a client
  355. program needs to draw this area, there is a pause as the effect code
  356. is sent from the server. On subsequent uses, however, the server knows
  357. that the client knows the effect, so only a short request to run it is
  358. sent over.
  359.  
  360.  
  361. Example - Code for the 'Inventory' Verb
  362.  
  363.  
  364. define tp_verbs proc v_inventory()bool:
  365.     int cash;
  366.     thing me;
  367.  
  368.     me := Me();
  369.     cash := me@p_pMoney;
  370.     if cash = 0 then
  371.     Print("You are broke.\n");
  372.     else
  373.     Print("You have ");
  374.     IPrint(cash);
  375.     if cash = 1 then
  376.         Print(" bluto.\n");
  377.     else
  378.         Print(" blutos.\n");
  379.     fi;
  380.     fi;
  381.     if ShowList(me@p_pCarrying, "You are carrying:\n") then
  382.     Print("You are not carrying anything.\n");
  383.     fi;
  384.     if not me@p_pHidden and CanSee(Here(), me) then
  385.     OPrint(FormatName(me@p_pName) + " takes inventory.\n");
  386.     fi;
  387.     true
  388. corp;
  389.  
  390. Verb0(G, "inventory", 0, v_inventory).
  391. Synonym(G, "inventory", "inv").
  392. Synonym(G, "inventory", "i").
  393.  
  394.  
  395. This routine returns a 'bool' (true/false) value, like other direct
  396. parsing routines. This is done so that if an error is encountered, the
  397. system can abort the handling of user input which contains several
  398. commands on one line, such as:
  399.  
  400.     go north. go east. west. get rope. go south. tie rope to rail
  401.  
  402. If such a parsing routine returns 'false', then the successive
  403. commands on the same line are not executed. In the case of
  404. 'inventory', there is nothing that can go wrong, so the function
  405. always returns 'true'.
  406.  
  407. This function has some local variables. They are valid only while the
  408. function is executing, and do not have to have names unique from local
  409. variables in other functions.
  410.  
  411. First, a local copy of the pointer to the current character, as
  412. yielded by calling the builtin "Me", is created. This is done since it
  413. is quicker to reference a local variable than to call a function.
  414. Next, the amount of money the character has is obtained. The '@'
  415. operator takes a 'thing' on the left and a property on the right, and
  416. returns the value of that property attached to the thing. Much more
  417. will be said about this later. The function then prints out an
  418. appropriate comment based on that amount. Next, it calls "ShowList",
  419. which is another routine in the scenario which prints the names of
  420. objects in a list, one per line, slightly indented. It is used here,
  421. when describing a room, and when looking inside a container. If the
  422. list is empty, it does not print anything, and returns 'true'. If the
  423. list is not empty, it prints its second parameter (here "You are
  424. carrying:\n") before printing the items in the list, and then returns
  425. 'false'. Thus, the code here will either print the list of objects the
  426. character is carrying (property 'p_pCarrying' on the character) headed
  427. by "You are carrying:\n", or will print "You are not carrying
  428. anything.\n" if the character is empty-handed.
  429.  
  430. The next 'if' statement is a bit more complicated. It's purpose is to
  431. allow other characters in the same room as the one doing the inventory
  432. to see what the first is doing, if appropriate. A character can be
  433. "hidden" (only wizards can do this in the current scenario), so that
  434. others cannot see them or what they are doing. 'CanSee' is another
  435. routine in the scenario, that determines whether or not there is light
  436. in the given room. There will be no light if the room is dark, no
  437. object in the room is emitting light, no character in the room is
  438. emitting light (wizards can make themselves glow), and no character in
  439. the room is carrying an object which is emitting light. 'OPrint' is a
  440. builtin function which displays the passed string to all characters in
  441. the same room as the active one. 'FormatName' is a builtin function
  442. which reformats a string from the AmigaMUD internal form into a more
  443. normal external form (e.g. turns "frog;small,green" into "small green
  444. frog"). Thus, if the active player is not a hidden wizard, and there
  445. is light in the current room, then all players in the current room
  446. will see the message "XXX takes inventory.\n", where XXX is the
  447. character's name.
  448.  
  449. The three lines after the function definition are directly executed
  450. statements which add the verbs "inventory", "inv" and "i" to the main
  451. grammar, as abbreviated by 'G'. 'Verb0' tells the system that there
  452. are no arguments expected for the verb. Other possibilities are
  453. 'Verb1' as in "examine <object>" and 'Verb2' as in "put the <object>
  454. into the <object>". The main grammar, G, is the one which is used to
  455. parse normal user commands when not in wizard mode. Other grammars are
  456. used for the building commands, etc. More details on parsing will be
  457. given later.
  458.  
  459.  
  460. Example - Code for the 'ShowList' Utility Routine
  461.  
  462.  
  463. define t_util proc utility public ShowList(list thing lt;
  464.                        string starter)bool:
  465.     int i;
  466.     thing object;
  467.     string s;
  468.     bool first;
  469.  
  470.     first := true;
  471.     for i from 0 upto Count(lt) - 1 do
  472.     object := lt[i];
  473.     if not object@p_oInvisible then
  474.         if first then
  475.         first := false;
  476.         Print(starter);
  477.         fi;
  478.         Print("  " + FormatName(object@p_oName) + "\n");
  479.     fi;
  480.     od;
  481.     first
  482. corp;
  483.  
  484.  
  485. A list in AmigaMUD can be indexed like a one-dimensional array. The
  486. builtin 'Count' takes any kind of list as its argument, and returns
  487. the number of elements in it. This routine simply runs down the
  488. elements in the passed list, and looks for any objects that are not
  489. marked as invisible. It prints each such one out, indented by two
  490. spaces, after the header passed by the caller. If no visible objects
  491. were found, 'ShowList' returns true, else it returns false.
  492.  
  493.  
  494. Example - the Code for Killing a Monster
  495.  
  496.  
  497. define t_fight proc KillMonster(thing monster)void:
  498.     string monsterName;
  499.     thing me, here;
  500.     list thing lt;
  501.     int i;
  502.  
  503.     me := Me();
  504.     monsterName := FormatName(monster@p_pName);
  505.     Print(monsterName + " is killed!\n");
  506.     if me@p_pHidden then
  507.     OPrint(monsterName + " is killed!\n");
  508.     else
  509.     OPrint(FormatName(me@p_pName) + " kills " + monsterName + "!\n");
  510.     fi;
  511.     me -- p_pCurrentTarget;
  512.     lt := monster@p_pCarrying;
  513.     if lt ~= nil then
  514.     here := Here();
  515.     i := Count(lt);
  516.     while i ~= 0 do
  517.         i := i - 1;
  518.         ignore DoDrop(here, monster, lt[i]);
  519.     od;
  520.     fi;
  521.     if monster ~= me then
  522.     i := monster@p_pMoney;
  523.     if i ~= 0 then
  524.         FindLoot((i + 1) / 2 + Random((i + 1) / 2));
  525.     fi;
  526.     fi;
  527.     ignore ForceAction(monster, DoUnShowIcon);
  528. corp;
  529.  
  530. This routine is executed whenever a character in the combat area (the
  531. "Proving Grounds") successfully vanquishes a monster. The routine
  532. prints informative messages to the player and anyone else around,
  533. causes all of the monster's possessions to be dropped, and gives the
  534. character a possible monetary reward. The final line of the function
  535. needs a bit more explaining. The builtin function 'ForceAction' forces
  536. the indicated character or NPC to execute the function passed as the
  537. second argument. This means that any code that affects "everyone else
  538. in the room" will also affect whoever is killing the monster. In this
  539. case, the routine called is responsible for removing the icon for the
  540. monster from the displays of everyone else in the room.
  541.  
  542.  
  543. Wizard-Mode Commands
  544.  
  545.  
  546. Most input entered while in wizard mode is either function definitions
  547. or statements in the programming language to be directly executed. A
  548. few special commands are available for convenience, however. They are:
  549.  
  550.     END-OF-FILE - an end-of-file condition will cause the client to
  551.     exit.
  552.  
  553.     bye - this command will cause the client to exit. Note that the
  554.     server keeps track of whether a character is in wizard mode
  555.     or not, so on the next connection, it will enter wizard mode
  556.     if that is the mode the character was last in. When not in
  557.     wizard mode, special scenario actions can be taken when a
  558.     character exits the game and when the character re-enters the
  559.     game. These are not performed when in wizard mode. Thus,
  560.     things like the initial display of the current location will
  561.     not happen automatically, and it may be necessary to look
  562.     around and/or move around to get it to appear.
  563.  
  564.     public
  565.     private
  566.     define/def - these three commands are used to define a symbol.
  567.     'public' will put the symbol into the global public symbol
  568.     table. 'private' will put the symbol into your private symbol
  569.     table, and 'define' will put the symbol into whatever table
  570.     you specify. There are two kinds of symbol definitions that
  571.     can be made. The first kind consists of a name for the symbol
  572.     followed by the definition of it, followed by a period.
  573.     Examples:
  574.  
  575.         public G CreateGrammar().
  576.         public p_pName CreateStringProp().
  577.         private HIT_LIMIT 72.
  578.         private room_table CreateTable().
  579.         define room_table westRoom CreateThing(genericRoom).
  580.         define room_table eastRoom CreateThing(genericRoom).
  581.  
  582.     The second kind of symbol definition defines a function. This
  583.     is done by using the reserved word 'proc' followed by the
  584.     function definition. See the previous example sections for
  585.     some of these. They will be discussed in more detail later.
  586.  
  587.     delete/del <table-name> <symbol> - this command will delete the
  588.     given symbol from the given table, if it can. It is similar
  589.     to running the 'DeleteSymbol' builtin. <table-name> can be
  590.     "private" or "public" as well as the name of a table.
  591.  
  592.     use <table-expression> - this command adds the specified symbol
  593.     table to the set of currently in-use tables. It is equivalent
  594.     to calling the 'UseTable' builtin. See the discussion of
  595.     tables in the 'Building' document.
  596.  
  597.     unuse <table-expression> - this command removes the specified
  598.     symbol table from the set of currently in-use tables. It is
  599.     equivalent to calling the 'UnUseTable' builtin.
  600.  
  601.     source <filename> - this command causes the contents of the named
  602.     file (on the client machine) to be read and processed. Files
  603.     sourced in this way can in turn contain other 'source'
  604.     commands. Doing this allows a large scenario to be split up
  605.     into a number of logical (and smaller) pieces. The filename
  606.     can be any legal AmigaDOS file path. Examples:
  607.  
  608.         source st:all.m
  609.         source df0:AmigaMUD/examples/speech.m
  610.  
  611.     When using the "MUD" client program, the 'Source' menu item is
  612.     equivalent to the 'source' command. Do not try to switch
  613.     between wizard mode and normal mode while sourcing files,
  614.     however, since the operation is asynchronous and will
  615.     probably not occur when you want it to.
  616.  
  617.     describe/desc/d <expression>. - this command prints out
  618.     information about the value of the requested expression. It is
  619.     the wizard mode command most often used interactively. The
  620.     output will depend on the type of the expression:
  621.  
  622.         void - a void value, i.e. no value, is printed as '<VOID>'
  623.  
  624.         status - a status value is printed symbolically, as
  625.         'succeed', 'continue' or 'fail'
  626.  
  627.         character - output for a character value is quite lengthy.
  628.         It consists of:
  629.  
  630.             - the character's sponsor - this is the character
  631.             who promoted this character to its current
  632.             status, if any.
  633.  
  634.             - the character's current location. This will be
  635.             the name of the location (room) the character
  636.             is in, if that room has a name, and a table
  637.             containing that name is in-use. Otherwise it
  638.             will just be '<THING>'.
  639.  
  640.             - the character's input action. This is the action
  641.             that all non-wizard-mode text input from the
  642.             player is passed to. It is normally some
  643.             general scenario parsing routine. The output
  644.             will be the name of the function if a table
  645.             containing that function is in-use, otherwise
  646.             it will be '<ACTION>'.
  647.  
  648.             - the character's raw key action. This is the
  649.             action which is called to process raw key
  650.             events occuring when the player hits a special
  651.             key, such as 'HELP', or a numeric keypad key.
  652.  
  653.             - the character's mouse down action. This is the
  654.             action which is called to process left-mouse-
  655.             button hits over identified regions of the
  656.             graphics window.
  657.  
  658.             - the character's button action. This is the
  659.             action which is called to process button hits
  660.             done with the mouse. Button-hits are clicks on
  661.             scenario-created "mouse-buttons" in the
  662.             graphics window.
  663.  
  664.             - the character's idle action. This is the action
  665.             which is called when the player leaves the
  666.             game when not in wizard mode.
  667.  
  668.             - the character's active action. This is the
  669.             action which is called when the player re-
  670.             enters the game not in wizard mode. It is
  671.             often used to do a 'look around' to establish
  672.             the display for the current location.
  673.  
  674.             - the character's status. This is one of:
  675.  
  676.             - normal
  677.             - apprentice
  678.             - wizard
  679.  
  680.             - the character's usecount. This indicates the
  681.             number of references to the character data
  682.             structure currently contained in the database.
  683.             The character cannot be deleted if this number
  684.             is non-zero. There will always be a reference
  685.             to the character from the 'Characters' symbol
  686.             table, and there will be another one resulting
  687.             from executing this command, and those two do
  688.             not count towards the total, but do show up.
  689.  
  690.             - the character's current non-wizard-mode prompt
  691.  
  692.             - the character's current password. This will only
  693.             be displayed for SysAdmin.
  694.  
  695.             - if the character is currently in wizard mode,
  696.             then '(in wizard mode)' is displayed
  697.  
  698.             - if the character is a new character, i.e. has
  699.             not yet connected and been initialized, then
  700.             '(new player)'.
  701.  
  702.             - the character's "thing" is displayed. This is
  703.             where all other changeable properties of the
  704.             character are stored. See the section here on
  705.             thing output for details.
  706.  
  707.         bool - a boolean value is printed as 'true' or 'false'
  708.  
  709.         int - an integer value is printed in decimal
  710.  
  711.         string - a string value is printed in quotes, with special
  712.         characters escaped as in source form
  713.  
  714.         thing - the output for a thing consists of a header
  715.         section, showing the fixed values that make up a
  716.         thing, followed by some number of property-value pairs
  717.         which are the contents of the thing. The fixed header
  718.         contains:
  719.  
  720.             - the thing's parent. This is the thing which this
  721.             thing starts inheriting properties from.
  722.  
  723.             - the thing's owner. This is the character who
  724.             currently owns the thing. When a thing is
  725.             created, it's owner is the effective
  726.             character at the time.
  727.  
  728.             - the thing's usecount. This is the number of
  729.             references to the thing from other entities in
  730.             the database. If this count goes to zero, then
  731.             the thing can be destroyed.
  732.  
  733.             - the thing's property count. This is the count of
  734.             the number of properties attached to the
  735.             thing. This does not count any properties that
  736.             may be inherited from ancestors.
  737.  
  738.             - the thing's status. This is one of:
  739.  
  740.             ts_private - only the owner of the thing can
  741.                 examine or change it
  742.  
  743.             ts_readonly - only the owner of the thing can
  744.                 change it, but anyone can examine it
  745.  
  746.             ts_wizard - any character with wizard status
  747.                 (or code running with that status) can
  748.                 change the thing, and anyone can examine
  749.                 the thing
  750.  
  751.             ts_public - anyone can change or examine the
  752.                 thing
  753.  
  754.         The contents of the thing, i.e. its properties, are
  755.         then displayed, indented two spaces. Each property
  756.         consists of the property, a colon and the value of
  757.         that property. If the property is defined in any in-
  758.         use table, then the name of the property is printed,
  759.         otherwise '<PROPERTY>' is printed. The value of the
  760.         property is printed much as being described here,
  761.         except that things are not shown expanded, but are
  762.         shown as a name, if one is found in an in-use table,
  763.         or as '<THING>'. Note that properties not known to the
  764.         current character are not displayed, unless the
  765.         current character is SysAdmin. Thus, adding more
  766.         tables to the "in-use" list can cause more properties
  767.         to be displayed on things. However, if a property is
  768.         not publically exported by the wizard who created it,
  769.         only that wizard and SysAdmin can see its value.
  770.  
  771.         action - actions, or functions, or procedures, are printed
  772.         with a short header describing the action. This header
  773.         contains:
  774.  
  775.             - the owner of the function. This is the character
  776.             who defined it.
  777.  
  778.             - the usecount of the function. An action cannot
  779.             be deleted unless this count goes to zero.
  780.  
  781.         Following this header is the definition of the
  782.         function, as pretty-printed by the system. For builtin
  783.         functions, which are pre-implemented, no function body
  784.         is shown. Also, if the owner of the function has made
  785.         it available in some public symbol table, but has not
  786.         marked the function itself as "public", the body is
  787.         not shown, unless it is SysAdmin who is looking. See a
  788.         later section on "Declarations" for an explanation of
  789.         the syntax of functions.
  790.  
  791.         table - only a header is printed for a table. The symbols
  792.         in the table can be displayed using the 'ShowTable'
  793.         builtin. The header for a table contains:
  794.  
  795.             - the owner of the table
  796.  
  797.             - the usecount of the table
  798.  
  799.             - the number of entries in the table
  800.  
  801.         grammar - a grammar is described much the same as a table.
  802.         The words in the grammar can be displayed using the
  803.         'ShowWords' builtin. The header for a grammar
  804.         contains:
  805.  
  806.             - the owner of the grammar
  807.  
  808.             - the usecount of the grammar
  809.  
  810.             - the number of words in the grammar
  811.  
  812.         lists - AmigaMUD has three kinds of lists: lists of 
  813.         integers, lists of things, and lists of actions. Each
  814.         is displayed as a list of values enclosed in braces.
  815.         Integers are shown directly in decimal, and things and
  816.         actions are shown as a symbol, if one is found in the
  817.         in-use tables, or as '<THING>' or '<ACTION>'.
  818.  
  819.         properties - properties are displayed symbolically if a
  820.         symbol for them is found in the set of in-use tables,
  821.         or just as '<PROPERTY>'.
  822.  
  823.         thing-status - a thing status (as returned by the builtin
  824.         'GetThingStatus') is displayed as one of:
  825.  
  826.             ts_private
  827.             ts_readonly
  828.             ts_wizard
  829.             ts_public
  830.  
  831.     edit/ed/e <function-name> - this command is used to interactively
  832.     edit a function. Only the body of a function can be changed -
  833.     its header can only be changed by deleting the function and
  834.     recreating it. Editing can only be done when using the "MUD"
  835.     client program, either locally or remotely, or when using the
  836.     "SMUD" client program locally. "SMUD" will always use an
  837.     external editor, as indicated by your "EDITOR" environment
  838.     variable, and "MUD" will use either an internal one or an
  839.     external one, depending on the "Editor" menu setting. See the
  840.     "MUD" document for details on how to use the internal editor.
  841.  
  842.     When the editing is done, the AmigaMUD programming language
  843.     parser attempts to "compile" the function. This can fail,
  844.     because of syntax or other errors, in which case the function
  845.     is left unchanged. With the "MUD" internal editor, the errors
  846.     are pointed out one at a time and the user can resubmit the
  847.     function at any point. When using an external editor, the user
  848.     can re-issue the 'edit' command, without giving a function
  849.     name, and will be left editing the file as it was when it was
  850.     submitted for compiling. This cycle can be repeated until the
  851.     function compiles, or the user gives up.
  852.  
  853.     replace <function-definition> - this command can be used, even
  854.     when not using the "MUD" or "SMUD" client programs, to change
  855.     the body of a function. The entire function must be re-
  856.     entered, including its header. E.g.
  857.  
  858.         > private proc doit()void:
  859.         :      Print("Hello\n");
  860.         : corp;
  861.         >
  862.         > replace doit()void:
  863.         :      int i;
  864.         :      for i from 1 upto 10 do
  865.         :          Print("i = " + IntToString(i) + "\n");
  866.         :      od;
  867.         : corp;
  868.         >
  869.  
  870.     This kind of editing is expected to be most useful in
  871.     conjunction with a terminal program which can do an ASCII-put
  872.     from a file on the remote machine. As with function editing,
  873.     the header of the function cannot be changed.
  874.  
  875.  
  876. Data Types
  877.  
  878. There are a number of data types in the AmigaMUD programming language.
  879. Not all are useable in all circumstances. The types are:
  880.  
  881.     void - this is not really a type. It is used as a function return
  882.     type to indicate that the function does not return a value
  883.     (and hence is actually a procedure and not a function). It is
  884.     also the type returned by statements, such as a 'for' loop.
  885.  
  886.     nil - this also is not really a type. It is the type of the
  887.     reserved word 'nil', which represents a non-value for things,
  888.     actions, tables, grammars and lists. This allows values of
  889.     those types to be tested for validity. No other use of this
  890.     type can occur.
  891.  
  892.     status - this type is a three-valued type, with values 'succeed',
  893.     'fail' and 'continue'. The interpretation of these three
  894.     values is at the discretion of the programmer, but a number of
  895.     builtin functions, such as 'FindName', return status values
  896.     with fixed interpretations on the values. It is suggested that
  897.     programmers use similar interpretations to avoid confusion:
  898.  
  899.         'succeed' - the operation has completed successfully
  900.         'fail' - the operation has failed
  901.         'continue' - the operation can be continued
  902.  
  903.     character - this type represents a reference to a player
  904.     character. It is used by a few builtin functions, such as
  905.     'Owner', 'Character', etc. Such a reference is not equivalent
  906.     to a reference to the character thing, such as is returned by
  907.     the 'Me' builtin. Builtins 'CharacterThing' and
  908.     'ThingCharacter' can be used to return one from the other.
  909.  
  910.     bool - this type is a two-valued type, with values 'true' and
  911.     'false'. It is the result of a comparison, and is the required
  912.     type for the condition in an 'if' construct or 'while'
  913.     statement. It is also used with the parsing builtins.
  914.  
  915.     int - this type is a signed 32 bit integer. In the programming
  916.     language, integers can be entered in decimal, hexadecimal,
  917.     octal, or binary. Only decimal conversions are provided as
  918.     builtins.
  919.  
  920.     string - this type represents a character string. The current
  921.     implementation limits strings to about 4000 characters in
  922.     length. Empty strings are allowed. In the programming
  923.     language, strings are surrounded by quotation marks (") and
  924.     may contain escapes for some non-printable characters.
  925.  
  926.     thing - this type represents a pointer to a thing. Things are the
  927.     basic database entity used to represent concepts such as
  928.     rooms and objects. There is a thing associated with each
  929.     player character or NPC. To the programmer, a thing is just a
  930.     set of attribute-value pairs. The attributes are properties
  931.     defined in the database by programmers, and their values can
  932.     be actions (functions), strings, integers, references to other
  933.     things, etc. Each thing also has an owner (the character who
  934.     currently owns it), and a parent (the thing, if any, to
  935.     inherit other properties from).
  936.  
  937.     action - actions are just functions or procedures. In AmigaMUD
  938.     they are first-class objects in that they can be stored in the
  939.     database, passed as parameters, and called indirectly. When a
  940.     function is called directly by another, the types and number
  941.     of the parameters and result are checked during the
  942.     compilation of the calling function. When a function is called
  943.     indirectly at runtime, this checking must be done dynamically,
  944.     after the called function has been identified. Thus, there can
  945.     be function-calling errors at runtime. Also, several builtins
  946.     take actions as parameters, and they check the parameters and
  947.     result of such actions at runtime.
  948.  
  949.     table - a table is a symbol table. It is a mapping from strings
  950.     (the symbols) to their values. Such tables are dynamic
  951.     entities and can be created, manipulated and destroyed at
  952.     runtime. They are stored in the database along with things,
  953.     properties, actions, etc. Since tables are values, it is
  954.     possible to have a symbol in a table whose value is another
  955.     table. This allows the construction of trees of symbol tables,
  956.     which is quite useful when organizing a large number of
  957.     symbols.
  958.  
  959.     grammar - a grammar is much like a table, in that it contains a
  960.     mapping from strings to values. In a grammar, however, the
  961.     values are special internal ones which the AmigaMUD system can
  962.     use to parse player input. The use of grammars is described in
  963.     the section on parsing.
  964.  
  965.     list int
  966.     list thing
  967.     list action - lists in AmigaMUD are somewhat of a cross between
  968.     linked lists and arrays. The size of them is dynamic, and
  969.     there are builtins to add and remove elements from both ends.
  970.     Their elements can be retrieved and modified by direct
  971.     indexing. Such indexing cannot extend the size of the list,
  972.     however.
  973.  
  974.     property bool
  975.     property int
  976.     property string
  977.     property thing
  978.     property action
  979.     property table
  980.     property grammar
  981.     property list int
  982.     property list thing
  983.     property list action - properties in AmigaMUD are the identifiers
  984.     for attribute-value pairs attached to things. The properties
  985.     are themselves first-class objects, however, so they can be
  986.     passed to functions as parameters, and returned as results.
  987.     Note that only certain types can be attached to things in
  988.     attribute-value pairs.
  989.  
  990.     <thing-status> - this type is not a full type in the language. It
  991.     has values 'ts_private', 'ts_readonly', 'ts_wizard' and
  992.     'ts_public'. It is only used as the result type of the builtin
  993.     'GetThingStatus' and the parameter to 'SetThingStatus'.
  994.  
  995. A few other types exist internally, but they are not generally visible
  996. to the programmer.
  997.  
  998.  
  999. Lexical Entities
  1000.  
  1001.  
  1002. The bottom-level sequences of characters that are known by a
  1003. programming language are called the tokens or lexemes of that
  1004. language. In the AmigaMUD programming language, spaces, tabs and
  1005. newlines are used to separate tokens that would otherwise appear to be
  1006. single tokens, but are otherwise ignored. In other words, the system
  1007. does not care, or even notice, what kind of indentation you use.
  1008.  
  1009. There are two kinds of comments in the language. One is the C-like
  1010. form consisting of characters enclosed within an opening "/*" and a
  1011. closing "*/". Unlike C, however, this kind of comment can be nested in
  1012. AmigaMUD, so that you can comment out a piece of code without worrying
  1013. about whether it has comments inside it. These comments are discarded
  1014. very early in the compilation process, so they do not affect runtime
  1015. at all. The second kind of comment is the 'note' statement. These are
  1016. actually stored in the database and displayed when the function
  1017. containing them is printed out. They also slow down execution of
  1018. functions containing them by a very small amount.
  1019.  
  1020. Newlines are normally ignored when you are in wizard mode. They are
  1021. significant, however, when typing wizard mode commands which accept
  1022. something other than a period-terminated expression as their
  1023. parameter. For example, entering just 'source' as an input line in
  1024. wizard mode will yield an error message about a missing file name.
  1025.  
  1026. The reserved words in the AmigaMUD programming language (those symbols
  1027. that cannot be used as regular identifiers by programmers) are:
  1028.  
  1029.     and, or, not, if, then, elif, else, fi, while, do, od, for,
  1030.     from, upto, case, incase, default, esac, ignore, call, note,
  1031.     proc, utility, wizard, public, corp, void, bool, int, string,
  1032.     thing, status, grammar, character, table, action, list,
  1033.     property, true, false, succeed, fail, continue, nil,
  1034.     ts_private, ts_readonly, ts_wizard, ts_public
  1035.  
  1036. Identifiers (user symbols) look like reserved words, but they aren't
  1037. give any predefined meaning by the system. They can be of any length,
  1038. and are composed of letters, digits and underscores. They must not
  1039. start with a digit. The following are legal identifiers:
  1040.  
  1041.     Fred ThisIsALongIdentifier so_is_this_one fazz_79 x3
  1042.  
  1043. Integers (numbers) can be entered in several forms in the AmigaMUD
  1044. programming language. The normal form is decimal (base 10). A number
  1045. can be prefixed with '0x' for hexadecimal (base 16) interpretation,
  1046. '0o' for octal (base 8) interpretation or '0b' for binary (base 2)
  1047. interpretation. The following are all valid integer constants:
  1048.  
  1049.     1234567890
  1050.     0xcaf4A
  1051.     0o777
  1052.     0b1010101010001010111
  1053.  
  1054. Integers are signed 32 bit quantities in AmigaMUD. Minus signs are not
  1055. part of integer constants - they are unary operators that can be
  1056. applied to them. Thus
  1057.  
  1058.     x := -13;
  1059.  
  1060. is perfectly legal - '-13' is interpreted as the unary '-' operator
  1061. and the integer constant 13.
  1062.  
  1063. String constants in AmigaMUD are similar to those in most programming
  1064. languages. They consist of any number of any characters enclosed in
  1065. quotation marks ("). Quotation marks and some unprintable characters
  1066. can be put inside string constants using an escape mechanism. Inside a
  1067. string, a backslash (\) is handled specially, depending on the
  1068. character following the backslash, as follows:
  1069.  
  1070.     \n - a newline character appears in the string
  1071.     \t - a tab character appears in the string
  1072.     \X, where X is any other character - a single X appears in the
  1073.     string. This is how backslashes and quotation marks can be put
  1074.     in string constants.
  1075.  
  1076. An important feature of string constants is the concept of a string
  1077. break. Two string constants, separated only by whitespace and /* */
  1078. comments, are concatenated together into one string constant. This is
  1079. done at "compile" time, and the internal representation used will be
  1080. that of a single string constant. When a function containing a long
  1081. string constant is printed, the string constant will be broken up
  1082. using string breaks in order to fit on the output lines. Such long
  1083. string constants are most often used in output messages, as in:
  1084.  
  1085.     Print("As you open the small wooden door, you detect a strange "
  1086.       "odour coming from the room beyond. The odour seems "
  1087.       "familiar, and you are about to identify it when you fall "
  1088.       "unconscious.");
  1089.  
  1090. The following operator and punctuation tokens are also recognized:
  1091.  
  1092.     .          used to end input in wizard mode
  1093.     =          simple equality test for various types
  1094.     ==          case ignoring comparison for strings
  1095.     ~          bitwise invert
  1096.     ~=          simple inequality test for various types
  1097.     < <= > >= comparison tests for integers and strings
  1098.     << >>     bitwise shift operators
  1099.     ><          bitwise exclusive-or operator
  1100.     :          punctuation in function headers, after the result type
  1101.     :=          assignment construct
  1102.     +          addition and string concatenation operator
  1103.     --          property deletion operator
  1104.     - * / %   integer arithmetic operators
  1105.     & |       integer bitwise operators
  1106.     ( )       parentheses for subexpressions, function calls, etc.
  1107.     , ;       separators for expressions and statements
  1108.     @          property lookup operator
  1109.     [ ]       brackets for list indexing
  1110.  
  1111.  
  1112. Declarations
  1113.  
  1114.  
  1115. The term "declaration" in the AmigaMUD programming language includes
  1116. the declaration and definition of functions, and the declarations of
  1117. local variables inside a function. AmigaMUD does not have global
  1118. variables - you must use properties attached to things instead.
  1119. Several examples of function (proc) definitions have already been seen
  1120. as examples. They consist of:
  1121.  
  1122.     - 'proc'
  1123.     - <optional 'utility'>
  1124.     - <optional 'public'>
  1125.     - <optional 'wizard'>
  1126.     - <the symbol for the proc>
  1127.     - '('
  1128.     - <formal parameter list>
  1129.     - ')'
  1130.     - result type
  1131.     - <optional local variable declarations>
  1132.     - <proc body>
  1133.     - 'corp'
  1134.  
  1135. The 'utility'/'public'/'wizard' tokens can be given in any order. If
  1136. the result type of the proc is 'void', then the <proc body>, which is
  1137. a semi-colon separated list of statements, must end in a statement. If
  1138. the result type of the proc is not void, then the <proc body> must end
  1139. in an expression of that type. That expression will yield the result
  1140. of the proc when the proc is executed. The <formal parameter list> is
  1141. just a semi-colon separated list of declarations, indicating the names
  1142. and types of the parameters that the proc will take when called. The
  1143. list is empty if the proc has no parameters. Note that, unlike some
  1144. languages, like Pascal, when calling a proc with no parameters, the
  1145. parentheses must still be given. This allows the system to distinguish
  1146. calling a proc from the use of the proc as a value (of type 'action').
  1147.  
  1148. A declaration of local variables or proc formal parameters consists of
  1149. at type followed by a comma-separated list of identifiers, and a
  1150. terminating semi-colon. Examples:
  1151.  
  1152.     int i, j, k;
  1153.     action a;
  1154.     property list int pli, l2prop;
  1155.     bool found, ok;
  1156.  
  1157. 'void' is not a valid type for a variable or parameter.
  1158.  
  1159. If a function is defined in a private table (one that is not available
  1160. to other wizards and apprentices), then there is no way for others to
  1161. look at it, unless it is attached to a thing as an action property, or
  1162. added to a visible action list. This does not prevent others from
  1163. executing it, however, such as when called by some other function. If
  1164. the proc is visible to others, then can use the 'describe' command, or
  1165. the DescribeSymbol builtin to look at it. Normally, however, they will
  1166. only be able to see the proc header. If the owner adds 'public' when
  1167. defining the function, then others will be able to see the full body
  1168. of the function, printy-printed for them.
  1169.  
  1170. Normally, when a function is called, the effective character and the
  1171. effective status are set to be the owner of the function. This gives
  1172. the function full access to properties, etc. owned by that character.
  1173. Sometimes, however, especially when SysAdmin is writing functions, the
  1174. setting of the effective state is not desired. In that case, the token
  1175. 'utility' can be added to the declaration. This arranges things so
  1176. that no change of effective character or status is done when the
  1177. function is called. This avoids giving access to private properties,
  1178. etc. The body of the function, however, must be careful to only use
  1179. publicly accessible properties.
  1180.  
  1181. If the token 'wizard' is added to a function definition, then the
  1182. function can only be called when the effective character is a wizard.
  1183. This allows wizards (and apprentices, although that isn't of much use)
  1184. to write wizard-only functions, just like some of the builtin ones.
  1185.  
  1186.  
  1187. Language Constructs
  1188.  
  1189.  
  1190. A number of constructs in AmigaMUD accept a sequence of statements or
  1191. an expression as a part of them. As in many programming languages,
  1192. statements in a sequence of statements are separated by semicolons.
  1193. Such a sequence can have an expression as its final element instead of
  1194. a statement, and thus the entire sequence can be used as an
  1195. expression. This is most often seen as the body of a function. Note
  1196. that this can only happen where specifically indicated - it is not
  1197. legal to replace any arbitrary expression with a sequence of
  1198. statements and an expression. This is trivial to implement, but I
  1199. deliberately did not do so, because of the confusion it can cause.
  1200. AmigaMUD does not have any constructs which only accept a single
  1201. statement as part of them, and thus it does not have any problem with
  1202. "dangling else"'s. All constructs are fully bracketed with reserved
  1203. words, hence there are no "begin"/"end" or "{"/"}" brackets needed.
  1204.  
  1205.  
  1206. The 'if' Construct
  1207.  
  1208.  
  1209. The AmigaMUD programming language has a standard set of language
  1210. constructs, including 'if's, 'while's, 'for's and 'case's. 'if's and
  1211. 'case's can be used as both statements and expressions, i.e. can
  1212. return a value or not return a value. An 'if' construct consists of:
  1213.  
  1214.     - 'if'
  1215.     - a bool expression (the condition)
  1216.     - 'then'
  1217.     - statements/expression to execute if condition is true
  1218.     - zero or more of:
  1219.     - 'elif'
  1220.     - a bool expression (the condition)
  1221.     - 'then'
  1222.     - statements/expression to execute if condition is true
  1223.     - optional:
  1224.     - 'else'
  1225.     - statements/expression to execute if all conditions are false
  1226.     - 'fi'
  1227.  
  1228. A simple example of an 'if' is:
  1229.  
  1230.     if flag then
  1231.     Print("Flag is true.\n");
  1232.     fi;
  1233.  
  1234. A more complex 'if' statement:
  1235.  
  1236.     if a <= b and not flag2 then
  1237.     if a = b then
  1238.         Print("Found!\n");
  1239.     else
  1240.         Print("Not found yet.\n");
  1241.     fi;
  1242.     elif a <= b or not flag2 then
  1243.     Print("Partly found.\n");
  1244.     else
  1245.     Print("No result.\n");
  1246.     fi;
  1247.  
  1248. Note that 'if' constructs can be nested. This is true in general of
  1249. the programming language - there are no limitations other than memory
  1250. available (nesting of constructs is limited only by the available
  1251. stack space - the required space is sufficient for a lot of nesting).
  1252. 'if' expressions can be used like this:
  1253.  
  1254.     max := if b > a then b else a fi;
  1255.  
  1256. An 'if' expression must always have an 'else' part, since there must
  1257. always be some value yielded. The various branches of an 'if'
  1258. expression must all yield the same type of value. The branches of an
  1259. 'if' expression can have statements preceeding the final result, all
  1260. separated by semicolons. E.g.
  1261.  
  1262.     result :=
  1263.     if a < b or b < c then
  1264.         Print("first case\n");
  1265.         a := b;
  1266.         c
  1267.     elif a < b then
  1268.         Print("second case\n");
  1269.         b := a;
  1270.         c
  1271.     else
  1272.         Print("third case\n");
  1273.         a := b;
  1274.         c := b;
  1275.         a
  1276.     fi;
  1277.  
  1278. This kind of construct works fine, but can be a little confusing, so
  1279. they should be used with care. Such large 'if' expressions are most
  1280. often used as the bodies of functions that return a result which
  1281. conditionally depends on something.
  1282.  
  1283.  
  1284. The 'while' Construct
  1285.  
  1286.  
  1287. A 'while' statement consists of:
  1288.  
  1289.     - 'while'
  1290.     - a bool expression (the condition)
  1291.     - 'do'
  1292.     - the loop body statement-sequence
  1293.     - 'od'
  1294.  
  1295. A 'while' loop is executed repeatedly until the condition yields
  1296. false. A 'while' loop does not return any value, i.e. it yields
  1297. 'void'. The condition can have statements before the final 'bool'
  1298. value, thus yielding a loop with its exit test in the middle. E.g.
  1299.  
  1300.     i := 10;
  1301.     while
  1302.     i := retrieveValue(i);
  1303.     i ~= 0
  1304.     do
  1305.     processValue(i);
  1306.     od;
  1307.  
  1308. Here, the sequence of execution will be:
  1309.  
  1310.     i := retrieveValue(10);    /* lets say this returns 8 */
  1311.     processValue(8);
  1312.     i := retrieveValue(8);    /* lets say this returns 3 */
  1313.     processValue(3);
  1314.     i := retrieveValue(3);    /* lets say this returns 0 */
  1315.  
  1316. and 'i' will be 0 after the 'while' loop. Programmers should use care
  1317. when using 'while' loops, since it may not be obvious when the loop
  1318. exits. The AmigaMUD server places an execution time limit on all
  1319. execution, so an infinite loop will be aborted, but, depending on what
  1320. SysAdmin has set that limit to, bad loops can have serious effects on
  1321. the performance of the server for other users. Also, aborting
  1322. execution can leave wizard-created data structures in an inconsistent
  1323. state.
  1324.  
  1325.  
  1326. The 'for' Construct
  1327.  
  1328.  
  1329. A 'for' statement consists of:
  1330.  
  1331.     - 'for'
  1332.     - local int variable name
  1333.     - 'from'
  1334.     - int expression (the start value)
  1335.     - 'upto'
  1336.     - int expression (the limit value)
  1337.     - 'do'
  1338.     - the loop body statement-sequence
  1339.     - 'od'
  1340.  
  1341. Like a 'while' loop, the 'for' loop does not return any value. The
  1342. start and limit expressions are evaluated once at the beginning of the
  1343. loop, and then the int variable is stepped by ones from the start
  1344. value upto the limit value, with the loop body executed once for each
  1345. such value. If the limit value is less than (signed integer
  1346. comparison) the start value, then the loop body is never executed.
  1347.  
  1348. 'for' loops are useful for stepping over fixed ranges, or through the
  1349. entries of a list, as in:
  1350.  
  1351.     GSetPen(nil, C_BLACK);
  1352.     for i from 1 upto 10 do
  1353.     GAMove(nil, i * 2, 30);
  1354.     for j from 1 upto 20 do
  1355.         GRMove(nil, 0, 1);
  1356.         GRDraw(nil, 0, 1);
  1357.     od;
  1358.     od;
  1359.  
  1360.     sum := 0;
  1361.     for j from 0 upto Count(listOfThings) - 1 do
  1362.     sum := sum + listOfThings[j]@intProperty;
  1363.     od;
  1364.     Print("Sum of values = ");
  1365.     IPrint(sum);
  1366.     Print(".\n");
  1367.  
  1368. When using a 'for' loop to scan down a list, make sure that code
  1369. executed in the body of the loop cannot modify the list itself. If it
  1370. can, you must use a 'while' loop, since the 'Count' of the elements in
  1371. the list will be changing.
  1372.  
  1373.  
  1374. The 'case' Construct
  1375.  
  1376.  
  1377. The 'case' construct is in some ways a generalization of the 'if'
  1378. construct. In other ways it is less general. It consists of:
  1379.  
  1380.     - 'case'
  1381.     - int expression (the selector)
  1382.     - one or more "case alternatives", which are:
  1383.     - 'default'
  1384.     - ':'
  1385.     - the alternative statements/expression
  1386.     or
  1387.     - a sequence of "case indexes", which are:
  1388.         - 'incase'
  1389.         - integer constant
  1390.         - ':'
  1391.     - the alternative statements/expression
  1392.     - 'esac'
  1393.  
  1394. Only one 'default' alternative can occur in any given 'case', and if
  1395. the 'case' is a 'case' expression, a 'default' alternative must occur.
  1396. Some examples:
  1397.  
  1398.     case whichButton
  1399.     incase LEFT_BUTTON:
  1400.     doMove(MOVE_LEFT);
  1401.     lastDirection := MOVE_LEFT;
  1402.     incase RIGHT_BUTTON:
  1403.     doMove(MOVE_RIGHT);
  1404.     lastDirection := MOVE_RIGHT;
  1405.     incase EXIT_BUTTON:
  1406.     incase LEAVE_BUTTON:
  1407.     incase OUT_BUTTON:
  1408.     doMove(MOVE_EXIT);
  1409.     lastDirection := MOVE_EXIT;
  1410.     default:
  1411.     if lastDirection ~= -1 then
  1412.         Print("You can't go that way.\n");
  1413.         lastDirection := -1;
  1414.     else
  1415.         Print("You still can't go that way.\n");
  1416.     fi;
  1417.     esac;
  1418.  
  1419.     result :=
  1420.     case retrieveThing()@intProperty
  1421.     incase 0:
  1422.         1
  1423.     incase 1:
  1424.         20
  1425.     default:
  1426.         Print("Illegal value encountered!\n");
  1427.         -1
  1428.     esac;
  1429.  
  1430. C programmers are cautioned that AmigaMUD case alternatives do not
  1431. fall through to the one beneath them. All 'case expressions' must have
  1432. a 'default' part, since some value must always result. 'case
  1433. statements' need not have one, and if the selector does not match any
  1434. of the case indexes, and the 'case' has no 'default' alternative, no
  1435. action is taken.
  1436.  
  1437.  
  1438. Function Calls
  1439.  
  1440.  
  1441. Function calls, whether to a builtin or to a user-defined function,
  1442. consist of the name of the function followed by a left parenthesis,
  1443. a comma separated list of the function parameters, and a right
  1444. parenthesis. The parentheses must be given even if the function has no
  1445. parameters. If no parentheses are given after a function name, then
  1446. the function itself is the value, with type 'action'. All function
  1447. parameters must be given, and must be of the same type as required by
  1448. the function header. If the function has a return-type of 'void', then
  1449. the function call itself yields 'void', i.e. it is a statement.
  1450. Otherwise, the function call yields the type of the function result.
  1451. Examples:
  1452.  
  1453.     Assume:
  1454.     proc f1(int i, j)int
  1455.     proc f2(string s1, s2)string
  1456.     proc f3(int i, string s)void
  1457.  
  1458.     Then:
  1459.  
  1460.     f3(f1(6, j + 7), f2("hello", "there") + "world");
  1461.  
  1462. If the function to be called is not known until run time, then the
  1463. above syntax cannot be used, since the result type of the function is
  1464. not known. Instead, the 'call' construct can be used. This form
  1465. consists of:
  1466.  
  1467.     - 'call'
  1468.     - '('
  1469.     - action expression (returns the function to call)
  1470.     - ','
  1471.     - the expected result type of the action
  1472.     - ')'
  1473.     - '('
  1474.     - the parameters for the function call
  1475.     - ')'
  1476.  
  1477. Since the expected result type is given explicitly, the system can
  1478. assume that type at "compile" time, and can check for it at run time.
  1479. The parameter count and types of the called function will always be
  1480. checked at run time. Examples:
  1481.  
  1482.     Print(call(Me()@p_pDescAction, string)() + "\n");
  1483.     i := i + call(if wantMax then max else min fi, int)(j, k);
  1484.  
  1485.  
  1486. Miscellaneous Constructs
  1487.  
  1488.  
  1489. Sometimes a function or a builtin yields a result that is not always
  1490. wanted - the call is being done for its side effects. In these cases,
  1491. it can be desireable to make it perfectly clear that the result is
  1492. being discarded, so, instead of assigning the result to some dummy
  1493. variable, the 'ignore' construct can be used. It consists of the
  1494. reserved word 'ignore' followed by any expression whose result is to
  1495. be discarded. 'ignore' always returns 'void'. E.g.
  1496.  
  1497.     ignore FindName(Me()@p_pCarrying, p_oName, "bottle");
  1498.     theBottle := FindResult();
  1499.  
  1500. As mentioned previously, there are two kinds of comments in the
  1501. AmigaMUD programming language. The first is the C-like one consisting
  1502. of an opening /*, comment text, and a closing */. The second kind of
  1503. comment is the 'note', which consists of all of the characters after
  1504. the 'note' keyword up to the end of the line. A 'note' comment is
  1505. stored in the database and will appear when the function containing it
  1506. is printed. For example:
  1507.  
  1508.     public proc complicated(thing th)void:
  1509.     note We are doing something complicated here, so be careful!
  1510.     if th@flag then
  1511.         ...
  1512.     else
  1513.         note flag not set, so don't try the tricky stuff.
  1514.         Print("The easy stuff!\n");
  1515.     fi;
  1516.     corp;
  1517.  
  1518. It is not necessary to put a semicolon after a note - they delimit
  1519. themselves, so the parser can recognize them.
  1520.  
  1521. The AmigaMUD system has limited support for direct, unnamed actions.
  1522. These are values of type 'action' and can be assigned and called. They
  1523. are typically only used in specialized circumstances, such as one-shot
  1524. actions produced by the "StringToAction" builtin. They must have
  1525. return type 'status', and consist of:
  1526.  
  1527.     - 'proc'
  1528.     - optional body statements
  1529.     - status result expression
  1530.     - 'corp'
  1531.  
  1532. For example, it is legal to do:
  1533.  
  1534.     myThing@actionProp :=
  1535.     proc
  1536.         Print("Hello there world!\n");
  1537.         succeed
  1538.     corp;
  1539.     ignore call(myThing@actionProp, status)();
  1540.  
  1541. Such procs have no symbol, so are usually less useful than normal
  1542. functions. Also, the forced 'status' result and lack of parameters or
  1543. local variables are a limiting factor. This facility may be
  1544. generalized in a future release, although there does not seem to be
  1545. much need for it.
  1546.  
  1547. The most common construct in the AmigaMUD programming language is the
  1548. assignment statement. Assignment statements consist of:
  1549.  
  1550.     - <assignment-left-hand-side>
  1551.     - ':='
  1552.     - <expression>
  1553.  
  1554. Assignment statements do not return any value, hence the concept of
  1555. "nested assignments" does not exist. Several different kinds of
  1556. <assignment-left-hand-side>'s are possible:
  1557.  
  1558.     - local variable or parameter name
  1559.     or
  1560.     - <list-expression>
  1561.     - '['
  1562.     - <int-expression>
  1563.     - ']'
  1564.     or
  1565.     - <thing-expression>
  1566.     - '@'
  1567.     - <property-expression>
  1568.  
  1569. The first variant is the obvious one of assigning a new value to a
  1570. local variable or parameter. The second is that of assigning a new
  1571. value to a specific element of a list. Note that the element indexed
  1572. by the <int-expression> must already be present in the list, else a
  1573. run-time indexing error will occur. Such indexing starts with 0 as the
  1574. first index, and "Count(<list>) - 1" as the last index.
  1575.  
  1576. The third form is used to assign a value to a property on a thing. The
  1577. property does not need to already exist - this method is the method
  1578. used to add new properties also.
  1579.  
  1580. Note that there are no global variables in AmigaMUD - values needed
  1581. outside of a single function must be stored as properties attached to
  1582. some thing.
  1583.  
  1584. Example assignment statements (all are of integer values, but the
  1585. same rules hold for any type of value):
  1586.  
  1587.     private th CreateThing(nil).
  1588.     private intProp CreateIntProp().
  1589.     private listProp CreateIntListProp().
  1590.  
  1591.     private proc testProc(int n)void:
  1592.     int i;
  1593.     list int li;
  1594.     
  1595.     i := 10;
  1596.     n := 100;
  1597.     li := CreateIntList();
  1598.     AddTail(li, 10);
  1599.     Addtail(li, 20);
  1600.     li[0] := 1;
  1601.     li[1] := 2;
  1602.     li(otherFunc()] := 6;
  1603.     th@intProp := 7;
  1604.     th@if i < 2 then intProp else otherIntProp fi := 8;
  1605.     th@listProp := li;
  1606.     th@listProp[1] := 9;
  1607.     call(th@thingProp@actionProp, list int)()[n] := i;
  1608.     corp;
  1609.  
  1610. Properties can be removed from things using the '--' construct:
  1611.  
  1612.     - <thing-expression>
  1613.     - '--';
  1614.     - <property-expression>
  1615.  
  1616. This construct is a statement - it does not return any value. Note
  1617. that it is not an error to try to delete a property from a thing when
  1618. that property does not exist on that thing. Examples:
  1619.  
  1620.     th1--intProp;
  1621.     thingFunc() -- thingPropFunc();
  1622.  
  1623.  
  1624. Expressions
  1625.  
  1626.  
  1627. Many examples of expressions have already been seen. This section will
  1628. simply list the full set of operators, in order of decreasing
  1629. precedence. The precedence of an operator is an indication of how
  1630. strongly it binds to its operands. A simple example is the following
  1631. expression:
  1632.  
  1633.     2 * 4 + 6 * 8
  1634.  
  1635. The value of this expression is 56, the sum of 2 * 4 and 6 * 8. This
  1636. is because the multiplications are done before the addition. The
  1637. multiplication operator, '*', has higher precedence than the addition
  1638. operator, '+'. The evaluation order of an expression can be changed by
  1639. the use of parentheses around a subexpression, as in:
  1640.  
  1641.     2 * (4 + 6) * 8
  1642.  
  1643. which has value 160, the product of 2, 4 + 6, and 8. So, for the
  1644. operators in the following descriptions, those described first will be
  1645. done before those described later, unless parentheses are introduced
  1646. to change the order of evaluation.
  1647.  
  1648. All expressions must start with bottom-level items. These are: 'if'-
  1649. expression, 'case'-expression, function call result, inline action,
  1650. parenthesized sub-expression, list reference, property reference,
  1651. identifier, string constant, integer constant, or any of the reserved
  1652. words 'false', 'true', 'succeed', 'fail', 'continue', 'nil',
  1653. 'ts_private', 'ts_readonly', 'ts_wizard', 'ts_public'.
  1654.  
  1655. 'if'- expressions, 'case'-expressions, function calls, inline actions
  1656. and parenthesized sub-expressions have all been covered previously.
  1657. Similarly, the bottom-level items were explained in the section on
  1658. lexical entities.
  1659.  
  1660. A list reference used as an expression looks exactly like the left-
  1661. hand-side of an assignment to a list element. The same rule holds -
  1662. the indexed element must exist in the list.
  1663.  
  1664. A property reference also looks just like the corresponding assignment
  1665. left-hand-side. When a property is being searched for on a thing, it
  1666. might not be found. If the thing has a parent thing (established when
  1667. the thing is created), then the search will continue with that parent
  1668. thing. Any value found on the parent will be used. Similarly, if the
  1669. value is not found on the parent, then the parent's parent will be
  1670. searched, etc. This "inheritance" of properties can be used to save
  1671. considerable space in the database, and to save a lot of effort when
  1672. creating new things which are all similar. Note that things can only
  1673. have a single parent - AmigaMUD does not have "multiple inheritance".
  1674.  
  1675. Good examples of the use of inheritance are the monsters in the
  1676. Proving Grounds in the standard scenario. Each monster has a model,
  1677. defined in the file "monsters.m", and when examples of that monster
  1678. are needed, they inherit most of their properties (name, description,
  1679. actions, speed, armour class, special actions, etc.) from the model.
  1680. Only values which need to be different (such as current hit points)
  1681. are stored on the specific instance. The fact that property assignment
  1682. only assigns to the descendant thing makes this use automatic.
  1683.  
  1684. A tricky use of inheritance can occur with things which inherit from
  1685. an ancestor, as in:
  1686.  
  1687.     private ancestor CreateThing(nil).
  1688.     private child CreateThing(ancestor).
  1689.     private intProp CreateIntProp().
  1690.  
  1691.     ancestor@intProp := 100.
  1692.  
  1693.     ...
  1694.  
  1695.     child@intProp := child@intProp - 1;
  1696.     if child@intProp = 0 then
  1697.         child -- intProp;
  1698.     fi;
  1699.  
  1700. This assignment statement will get the 100 value from the ancestor
  1701. thing the first time it is executed, and will add the property with
  1702. value 99 to the child. On successive executions, it will modify the
  1703. property on the child. When the value reaches 0, the property is
  1704. deleted, and will again inherit the 100 from the ancestor.
  1705.  
  1706. If a property which is not present on the thing is referenced, the
  1707. value yielded depends on the type of the property:
  1708.  
  1709.     status - fail
  1710.     bool - false
  1711.     int - 0
  1712.     string - "" (an empty string)
  1713.     thing, action, grammar, list - nil
  1714.  
  1715. This defaulting of values is usually useful, but can occasionally be a
  1716. bit of a nuisance. The main use is to save storage - the programmer
  1717. can count on these values for missing properties, and hence can
  1718. arrange to not store them explicitly. This works quite well for flag
  1719. values.
  1720.  
  1721.  
  1722. Unary Negation: -
  1723.  
  1724.     This operator appears before an int expression and negates the
  1725.     value of the expression. E.g.
  1726.  
  1727.     -6
  1728.     -(intvar * 7)
  1729.     -th@func(7, -6)
  1730.  
  1731. Bitwise And: &
  1732. Bitwise Exclusive-Or: ><
  1733. Bitwise Shift Left: <<
  1734. Bitwise Shift Right: >>
  1735.  
  1736.     These operators all operate on int values. They all have the same
  1737.     precedence, so are evaluated left-to-right when used together in
  1738.     an expression. The Bitwise And operator combines two int values in
  1739.     a bit-by-bit fashion - each of the 32 bits of the result is a '1'
  1740.     bit only if both of the corresponding bits in the operands were
  1741.     also '1' bits. The Bitwise Exclusive-Or operator yields a '1' bit
  1742.     in the result only if the corresponding bits in the operands are
  1743.     different. The Shift-Left operator shifts its left-hand operand
  1744.     left by the number of bits specified in its right-hand operand.
  1745.     Similarly, the Shift-Right operator shifts its left-hand operand
  1746.     right by the number of bits specified in its right-hand operand.
  1747.     If the right-hand operand to a shift operator is negative, it is
  1748.     not defined what the result will be. Also, if the right-hand
  1749.     operand is greater than 32 (the number of bits in the left-hand
  1750.     operand), the result is not defined. E.g.
  1751.  
  1752.     0b1100 & 0b0101 => 0b0100
  1753.     0b1100 >< 0b0101 => 0b1001
  1754.     0b001100 << 2 => 0b110000
  1755.     0b001100 << 3 => 0b1100000
  1756.     0b001100 >> 2 => 0b000011
  1757.  
  1758.     a & b >< c << d >> e == ((((a & b) >< c) << d) >> e)
  1759.  
  1760. Bitwise Inclusive-Or: |
  1761.  
  1762.     This operator requires two int operands and returns an int result.
  1763.     Each of the 32 bits in the result is a '1' if the corresponding
  1764.     bit in either of the operands is a '1'. E.g.
  1765.  
  1766.     0b1100 | 0b0101 => 0b1101
  1767.     a & b | c << d | e == (a & b) | (c << d) | e
  1768.  
  1769. Integer Multiplication: *
  1770. Integer Division: /
  1771. Integer Remainder: %
  1772.  
  1773.     These operators take a pair of int operands and yield an int
  1774.     result. Division or remainder by zero will be trapped at runtime.
  1775.  
  1776. Integer Addition: +
  1777. Integer Subtraction: -
  1778. String Concatenation: +
  1779.  
  1780.     Note that both integer addition and string concatenation have the
  1781.     same operator symbol. The operations are distinguished by the
  1782.     types of their operands. E.g.
  1783.  
  1784.     6 + 128 => 134
  1785.     6 - 128 => -122
  1786.     "hello" + "world" => "helloworld"
  1787.     "hello " + "world" => "hello world"
  1788.     "" + "" => ""
  1789.  
  1790. Integer Comparisons: <= < = ~= > >=
  1791. String Comparisons: <= < = ~= == > >=
  1792. Other Comparisons: = ~=
  1793.  
  1794.     All comparisons yield a bool value. All comparisons must have
  1795.     operands which are both of the same type. The integer comparisons
  1796.     are 32 bit signed integer comparisons. The string comparisons use
  1797.     comparisons based on the ASCII values of the characters in the
  1798.     strings. The '==' operator converts all letters to upper case (or
  1799.     lower case if you prefer!) before doing the comparison. It is
  1800.     useful when dealing with user input that might be capitalized.
  1801.     Things, actions, lists, properties, etc. can be compared for
  1802.     equality or inequality. E.g.
  1803.  
  1804.     6 < 12 => true
  1805.     -6 < -12 => false
  1806.     "hello" = "hello" => true
  1807.     "hello" <= "hello" => true
  1808.     "hello" = "Hello" => false
  1809.     "hello" == "Hello" => true
  1810.  
  1811. Logical Not: not
  1812.  
  1813.     This prefix operator reverses the logical value of its bool
  1814.     operand. E.g.
  1815.  
  1816.     not true => false
  1817.     not false => true
  1818.     not 6 < 10 => false
  1819.  
  1820. Logical And: and
  1821.  
  1822.     This operator takes two bool operands and returns a bool result
  1823.     that is true only if both operands are true. Technically, this is
  1824.     a language construct rather than a true operator, since the
  1825.     AmigaMUD interpreter will not even try to evaluate the right-hand
  1826.     operand if the left-hand operand evaluates to false, since it
  1827.     knows that the right-hand operand will not affect the final
  1828.     result. This behaviour is part of the language definition and will
  1829.     not change; thus the programmer is correct to write things like:
  1830.  
  1831.     th ~= nil and th@field = 2
  1832.  
  1833. Logical Or: or
  1834.  
  1835.     This operator takes two bool operands and returns a bool result
  1836.     that is true if either of its operands is true. Similar to the
  1837.     'and' operator, the 'or' operator will not evaluate its right-hand
  1838.     operand if its left-hand operand is "true".
  1839.  
  1840.  
  1841. Further Reading
  1842.  
  1843. This document has informally defined the AmigaMUD programming
  1844. language. This information allows wizards and apprentices to write and
  1845. run valid AmigaMUD programs, but it has not given enough information
  1846. to allow them to write meaningful programs, or programs that fit in
  1847. with the supplied standard scenario. Further documents relevant to
  1848. programming are:
  1849.  
  1850.     ProgConcepts.txt - discusses some classes of builtin functions and
  1851.     how to use them. This includes parsing, effects handling,
  1852.     graphics, character manipulation, etc.
  1853.  
  1854.     Builtins.txt - this is a reference manual for the builtin
  1855.     functions. It lists and describes all of the builtins, in
  1856.     alphabetical order.
  1857.  
  1858.     Scenario.txt - this document is a rambling discussion of how the
  1859.     standard scenario is set up, the utility functions it
  1860.     provides, how to build from it, and how to change how it
  1861.     works.
  1862.